1   /*
2    * Javassist, a Java-bytecode translator toolkit.
3    * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4    *
5    * The contents of this file are subject to the Mozilla Public License Version
6    * 1.1 (the "License"); you may not use this file except in compliance with
7    * the License.  Alternatively, the contents of this file may be used under
8    * the terms of the GNU Lesser General Public License Version 2.1 or later,
9    * or the Apache License Version 2.0.
10   *
11   * Software distributed under the License is distributed on an "AS IS" basis,
12   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13   * for the specific language governing rights and limitations under the
14   * License.
15   */
16  
17  package scouter.javassist.bytecode;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.DataInputStream;
21  import java.io.IOException;
22  import java.util.HashMap;
23  import java.util.Map;
24  
25  import scouter.javassist.bytecode.AttributeInfo;
26  import scouter.javassist.bytecode.ConstPool;
27  import scouter.javassist.bytecode.AnnotationsAttribute.Copier;
28  import scouter.javassist.bytecode.AnnotationsAttribute.Parser;
29  import scouter.javassist.bytecode.AnnotationsAttribute.Renamer;
30  import scouter.javassist.bytecode.annotation.Annotation;
31  import scouter.javassist.bytecode.annotation.AnnotationsWriter;
32  
33  
34  /**
35   * A class representing <code>RuntimeVisibleAnnotations_attribute</code> and
36   * <code>RuntimeInvisibleAnnotations_attribute</code>.
37   *
38   * <p>To obtain an ParameterAnnotationAttribute object, invoke
39   * <code>getAttribute(ParameterAnnotationsAttribute.invisibleTag)</code>
40   * in <code>MethodInfo</code>.
41   * The obtained attribute is a
42   * runtime invisible annotations attribute.  
43   * If the parameter is
44   * <code>ParameterAnnotationAttribute.visibleTag</code>, then the obtained
45   * attribute is a runtime visible one.
46   */
47  public class ParameterAnnotationsAttribute extends AttributeInfo {
48      /**
49       * The name of the <code>RuntimeVisibleParameterAnnotations</code>
50       * attribute.
51       */
52      public static final String visibleTag
53          = "RuntimeVisibleParameterAnnotations";
54  
55      /**
56       * The name of the <code>RuntimeInvisibleParameterAnnotations</code>
57       * attribute.
58       */
59      public static final String invisibleTag
60          = "RuntimeInvisibleParameterAnnotations";
61      /**
62       * Constructs
63       * a <code>Runtime(In)VisibleParameterAnnotations_attribute</code>.
64       *
65       * @param cp            constant pool
66       * @param attrname      attribute name (<code>visibleTag</code> or
67       *                      <code>invisibleTag</code>).
68       * @param info          the contents of this attribute.  It does not
69       *                      include <code>attribute_name_index</code> or
70       *                      <code>attribute_length</code>.
71       */
72      public ParameterAnnotationsAttribute(ConstPool cp, String attrname,
73                                           byte[] info) {
74          super(cp, attrname, info);
75      }
76  
77      /**
78       * Constructs an empty
79       * <code>Runtime(In)VisibleParameterAnnotations_attribute</code>.
80       * A new annotation can be later added to the created attribute
81       * by <code>setAnnotations()</code>.
82       *
83       * @param cp            constant pool
84       * @param attrname      attribute name (<code>visibleTag</code> or
85       *                      <code>invisibleTag</code>).
86       * @see #setAnnotations(Annotation[][])
87       */
88      public ParameterAnnotationsAttribute(ConstPool cp, String attrname) {
89          this(cp, attrname, new byte[] { 0 });
90      }
91  
92      /**
93       * @param n     the attribute name.
94       */
95      ParameterAnnotationsAttribute(ConstPool cp, int n, DataInputStream in)
96          throws IOException
97      {
98          super(cp, n, in);
99      }
100 
101     /**
102      * Returns <code>num_parameters</code>. 
103      */
104     public int numParameters() {
105         return info[0] & 0xff;
106     }
107 
108     /**
109      * Copies this attribute and returns a new copy.
110      */
111     public AttributeInfo copy(ConstPool newCp, Map classnames) {
112         Copier copier = new Copier(info, constPool, newCp, classnames);
113         try {
114             copier.parameters();
115             return new ParameterAnnotationsAttribute(newCp, getName(),
116                                                      copier.close());
117         }
118         catch (Exception e) {
119             throw new RuntimeException(e.toString());
120         }
121     }
122 
123     /**
124      * Parses the annotations and returns a data structure representing
125      * that parsed annotations.  Note that changes of the node values of the
126      * returned tree are not reflected on the annotations represented by
127      * this object unless the tree is copied back to this object by
128      * <code>setAnnotations()</code>.
129      *
130      * @return Each element of the returned array represents an array of
131      * annotations that are associated with each method parameter.
132      *      
133      * @see #setAnnotations(Annotation[][])
134      */
135     public Annotation[][] getAnnotations() {
136         try {
137             return new Parser(info, constPool).parseParameters();
138         }
139         catch (Exception e) {
140             throw new RuntimeException(e.toString());
141         }
142     }
143 
144     /**
145      * Changes the annotations represented by this object according to
146      * the given array of <code>Annotation</code> objects.
147      *
148      * @param params        the data structure representing the
149      *                      new annotations. Every element of this array
150      *                      is an array of <code>Annotation</code> and
151      *                      it represens annotations of each method parameter.
152      */
153     public void setAnnotations(Annotation[][] params) {
154         ByteArrayOutputStream output = new ByteArrayOutputStream();
155         AnnotationsWriter writer = new AnnotationsWriter(output, constPool);
156         try {
157             int n = params.length;
158             writer.numParameters(n);
159             for (int i = 0; i < n; ++i) {
160                 Annotation[] anno = params[i];
161                 writer.numAnnotations(anno.length);
162                 for (int j = 0; j < anno.length; ++j)
163                     anno[j].write(writer);
164             }
165 
166             writer.close();
167         }
168         catch (IOException e) {
169             throw new RuntimeException(e);      // should never reach here.
170         }
171 
172         set(output.toByteArray());
173     }
174 
175     /**
176      * @param oldname       a JVM class name.
177      * @param newname       a JVM class name.
178      */
179     void renameClass(String oldname, String newname) {
180         HashMap map = new HashMap();
181         map.put(oldname, newname);
182         renameClass(map);
183     }
184 
185     void renameClass(Map classnames) {
186         Renamer renamer = new Renamer(info, getConstPool(), classnames);
187         try {
188             renamer.parameters();
189         } catch (Exception e) {
190             throw new RuntimeException(e);
191         }
192     }
193 
194     void getRefClasses(Map classnames) { renameClass(classnames); }
195 
196     /**
197      * Returns a string representation of this object.
198      */
199     public String toString() {
200         Annotation[][] aa = getAnnotations();
201         StringBuilder sbuf = new StringBuilder();
202         int k = 0;
203         while (k < aa.length) {
204             Annotation[] a = aa[k++]; 
205             int i = 0;
206             while (i < a.length) {
207                 sbuf.append(a[i++].toString());
208                 if (i != a.length)
209                     sbuf.append(" ");
210             }
211 
212             if (k != aa.length)
213                 sbuf.append(", ");
214         }
215 
216         return sbuf.toString();
217 
218     }
219 }